home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 431_01 / comio.c < prev    next >
C/C++ Source or Header  |  1994-10-02  |  6KB  |  260 lines

  1. /*
  2.   serial i/o stuff. does not use the 16550a FIFO.
  3.   i do not track line errors such as parity, overrun, or framing as
  4.   it would require 2 bytes / character instead of 1 and i want to
  5.   save some memory. since i do various block checks internally, it
  6.   is also redundant.
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <dos.h>
  11. #include <conio.h>
  12. #include <string.h>
  13.  
  14. #include "comio.h"
  15. #include "myalloc.h"
  16. #include "local.h"
  17.  
  18. extern void com0_init(void);
  19. extern void com0_shutdown(void);
  20. extern void interrupt com0();
  21.  
  22. /*
  23.     port 0x3f8 / irq 4 / int c = #1
  24.     port 0x2f8 / irq 3 / int b = #2
  25. */
  26.  
  27. /*
  28.   transmit / recieve buffer
  29. */
  30. int TRB, /* transmit/recieve character buffer */
  31.     IER, /* interrupt enable                  */
  32.     IIR, /* interrupt identification          */
  33.     LCR, /* line control                      */
  34.     MCR, /* modem control                     */
  35.     LSR, /* line status                       */
  36.     MSR; /* modem status                      */
  37.  
  38. int    xmitlen;      /* number of bytes left to transmit  */
  39. BYTE  *xmitptr;      /* next byte in transmit buffer      */
  40. BYTE  *rcvbuf;       /* recieve buffer (queue)            */
  41.  
  42. int    rcv_head,
  43.        rcv_tail,
  44.        rcv_size;     /* actual buffer size MUST BE one less than a power
  45.                         of 2 */
  46.  
  47. LOCAL int    irq;          /* irq address                       */
  48. LOCAL int    irq_int;      /* interrupt address                 */
  49. LOCAL void interrupt (*oldint14)();
  50.  
  51. DWORD  total_sent;
  52. DWORD  total_rcvd;
  53.  
  54. /*
  55.   i read as a footnote somewhere that the IIR bits are not always
  56.   accurate, thus the reason i check LSR before doing any work...
  57.  
  58.   i loop in here to catch high speed transmission in bursts
  59. */
  60. void CommIO(void)
  61. {
  62.   do {
  63.     int stat=inportb(LSR);         /* get line status */
  64.     inportb(MSR);                  /* ignore modem status */
  65.     /*
  66.       if byte pending in buffer, get it
  67.     */
  68.     if (stat & 0x01) {
  69.       int byte=inportb(TRB);
  70.       total_rcvd++;
  71.  
  72.       if (((rcv_head+1) & rcv_size) != rcv_tail)
  73.         rcvbuf[rcv_head++]=byte;
  74.       rcv_head &= rcv_size;
  75.     }
  76.  
  77.     /*
  78.       if byte ready to be sent, send it
  79.     */
  80.     if (xmitlen && (stat & 0x20)) {
  81.       total_sent++;
  82.       outportb(TRB, *(xmitptr++));
  83.       xmitlen--;
  84.     }
  85.   } while ((!(inportb(IIR) & 0x01)));
  86. }
  87.  
  88. void CommIO_shutdown(void)
  89. {
  90.   if (irq_int) {
  91.     outportb(0x21, inportb(0x21) | (1 << irq));
  92.     setvect(irq_int, *oldint14);
  93.     irq_int=0;
  94.     outportb(IER, 0);
  95.     com0_shutdown();
  96.     my_free(rcvbuf);
  97.   }
  98. }
  99.  
  100. int MODE;
  101. /*
  102.   com       = 1, 2, 3, 4
  103.   mode      = or'd options
  104.   baud      = baud rate
  105.   pirq      = irq # override (-1 for default), 0 = use polled
  106.   pbaseport = base port override (-1 for default)
  107. return
  108.   0 if initialized, else fail code
  109. */
  110. int CommIO_Initialize(int  com,
  111.                       int  mode,
  112.                       long baud,
  113.                       int  pirq,
  114.                       int  pbaseport)
  115. {
  116.   int base;
  117.  
  118.   MODE=mode;
  119.   xmitlen=0;
  120.   xmitptr=0;
  121.   rcv_size=2047;
  122.   rcvbuf=my_malloc(rcv_size+1);
  123.   if (!rcvbuf)
  124.     return 1;
  125.  
  126.   com--;
  127.   base    = (pbaseport < 0) ? *(WORD *) MK_FP(0x40, 2*com) : pbaseport;
  128.   irq     = (pirq < 0) ? 0x04-(com & 0x01): pirq;
  129.   irq_int = irq ? 0x08+irq : 0;
  130.  
  131.   TRB =(base);
  132.   IER =(base+1);
  133.   IIR =(base+2);
  134.   LCR =(base+3);
  135.   MCR =(base+4);
  136.   LSR =(base+5);
  137.   MSR =(base+6);
  138.  
  139.   baud = 115200/baud;
  140.   if (!baud)   /* must be at least 1 */
  141.     baud++;
  142.   outportb(LCR, mode | 0x80);           /* set baud rate & mode */
  143.   outportb(TRB, baud & 0xff);
  144.   outportb(TRB+1, baud >> 8);
  145.   outportb(LCR, mode);
  146.   outportb(MCR, 0);
  147.  
  148.   com0_init();
  149.  
  150.   if (irq_int) {
  151.     oldint14=getvect(irq_int);
  152.     setvect(irq_int, com0);
  153.     outportb(0x21, inportb(0x21) & ~(1 << irq)); /* enable the interrupt */
  154.     outportb(IER, 0x03);           /* enable line status change interrupt */
  155.     do {
  156.       inportb(TRB);   /* clear any pending bytes        */
  157.       inportb(LSR);   /* clear the line status register */
  158.       inportb(MSR);
  159.     } while (!(inportb(IIR) & 0x01));
  160.     outportb(MCR, 0x0c);
  161.   } else {
  162.     outportb(IER, 0x00);
  163.     outportb(MCR, 0x00);
  164.   }
  165.   return 0;
  166. }
  167.  
  168. void CommIO_Transmit(void *buf, int len)
  169. {
  170.   xmitlen=0;                           /* clear pending xmit            */
  171.   while ((inportb(LSR) & 0x20) == 0);  /* wait for xmit buffer to empty */
  172.   if (len) {
  173.     xmitptr=((char *) buf)+1;
  174.     outportb(TRB, *(char *) buf);        /* transmit first character      */
  175.     xmitlen=len-1;                       /* set length to buffer - 1      */
  176.   }
  177. }
  178.  
  179. /*
  180.   return the next byte in the queue, -1 on error
  181. */
  182. int  CommIO_GetByte(void)
  183. {
  184.   if (rcv_head == rcv_tail)
  185.     return -1;
  186.   else {
  187.     int byte=rcvbuf[rcv_tail++];
  188.     rcv_tail &= rcv_size;
  189.     return byte;
  190.   }
  191. }
  192.  
  193. /*
  194.   return TRUE if there are bytes in the queue, else FALSE
  195. */
  196. int  CommIO_RecievePending(void)
  197. {
  198.   return (rcv_tail != rcv_head);
  199. }
  200.  
  201. /*
  202.   return TRUE if we are mid-transmit, else FALSE
  203. */
  204. int CommIO_TransmitPending(void)
  205. {
  206.   return (xmitlen);
  207. }
  208.  
  209. /*
  210.   return >= 0 == byte
  211.          <  0 == error
  212.   timeout in 1/18 sec
  213. */
  214. int  CommIO_WaitByte(unsigned timeout)
  215. {
  216.   long clk=CLOCK;
  217.  
  218.   while (!CommIO_RecievePending() && (labs(CLOCK-clk) < timeout));
  219.   return CommIO_GetByte();
  220. }
  221.  
  222. /*
  223.   flush the recieve queue
  224. */
  225. void  CommIO_FlushBuffer(void)
  226. {
  227.   rcv_head=rcv_tail=0;
  228. }
  229.  
  230. void CommIO_TransmitLoop(void *buf, int len)
  231. {
  232.   char *out=buf;
  233.  
  234.   xmitlen=0;                           /* clear pending xmit            */
  235.   outportb(LCR, MODE);
  236.   while ((inportb(LSR) & 0x20) == 0);  /* wait for xmit buffer to empty */
  237.   while (len--) {
  238.     outportb(TRB, *(out++));
  239.     total_sent++;
  240.     while ((inportb(LSR) & 0x20) == 0);  /* wait for xmit buffer to empty */
  241.   }
  242. }
  243.  
  244. int  CommIO_WaitByteLoop(unsigned timeout)
  245. {
  246.   long clk=CLOCK;
  247.  
  248.   while (!(inportb(LSR) & 0x01)) {
  249.     if (labs(CLOCK-clk) >= timeout) {
  250.       outportb(LCR, MODE);
  251.       return -1;
  252.     }
  253.   }
  254.   total_rcvd++;
  255.   {
  256.     int key=inportb(TRB);
  257.     return key;
  258.   }
  259. }
  260.